﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Geometry
{
    /// <summary>
    /// Providing vector representation, with the optional starting point of the vector
    /// </summary>
    public class Vector
    {
        /// <summary>
        /// Współrzędna x wektora
        /// </summary>
        public double a { get; private set; }
        /// <summary>
        /// Współrzędna y wektora
        /// </summary>
        public double b { get; private set; }
        /// <summary>
        /// Kąt wektora (Między 0 a 2PI, NIE MOŻE BY UJEMNY)
        /// </summary>
        public Angle angle { get; private set; }
        /// <summary>
        /// Punkt zaczepienia wektora
        /// </summary>
        public Point start_point { get; set; }

        #region Vector Contructors

        /// <summary>
        /// Deflaut 0,0 Vector constructor
        /// </summary>
        public Vector()
        {
            a = 0;
            b = 0;
            angle = new Angle();
            start_point = new Point();
        }

        /// <summary>
        /// Vector parameters constructor, starting point=0,0
        /// </summary>
        /// <param name="la">The X Coordinate</param> 
        /// <param name="lb">The Y Coordinate</param>
        public Vector(double la, double lb)
        {
            a = la;
            b = lb;
            angle = new Angle();
            CalculAngle();
            start_point = new Point();
        }

        /// <summary>
        /// Vector point to point constructor, starting point=p1
        /// </summary>
        /// <param name="p1">Vector From</param>
        /// <param name="p2">Vector To</param>
        public Vector(Point p1, Point p2)
        {
            a = p2.x - p1.x;
            b = p2.y - p1.y;
            angle = new Angle();
            CalculAngle();
            start_point = new Point(p1);
        }

        /// <summary>
        /// Vector angle constructor, starting point=0,0, X coordinate=1
        /// </summary>
        /// <param name="angle">Angle from the X axis</param>
        public Vector(Angle an)
        {
            start_point = new Point();

            CalculAB(an);
        }

        /// <summary>
        /// Copy constructor
        /// </summary>
        public Vector(Vector vec)
        {
            a = vec.a;
            b = vec.b;
            angle = new Angle(vec.angle);
        }

        #endregion

        public static Vector operator +(Vector one, Vector two)
        {
            double a = one.a + two.a;
            double b = one.b + two.b;

            return new Vector(a, b);
        }

        public static Vector operator -(Vector one, Vector two)
        {
            Vector minus_two=new Vector(two);
            minus_two.ChangeDirection();

            return new Vector(one + minus_two);
        }

        /// <summary>
        /// Check if vectors are parallel (rounded)
        /// </summary>
        public static bool AreParallel(Vector v, Vector v1)
        {
            if (Math.Round((v.a * v1.b), 5) == Math.Round((v.b * v1.a), 5)) return true;
            return false;
        }

        /// <summary>
        /// Sprawdza czy wektory są przeciwnie skierowane
        /// </summary>
        /// <param name="v">First Vector</param>
        /// <param name="v1">Second Vector</param>
        /// <returns>Returns true if vector are reversed</returns>
        public static bool AreReversed(Vector v, Vector v1)
        {
            if (!AreParallel(v, v1)) return false;
            if ((v.a * v1.a + v.b * v1.b) < 0) return true;
            return false;
        }

        /// <summary>
        /// Chceck if vectors are parallel and have the same direction
        /// </summary>
        /// <param name="v">First Vector</param>
        /// <param name="v1">Second Vector</param>
        public static bool AreNotReversed(Vector v, Vector v1)
        {
            if (!AreParallel(v, v1)) return false;
            if ((v.a * v1.a + v.b * v1.b) > 0) return true;
            return false;
        }

        /// <summary>
        /// Get the lenght of the Vector
        /// </summary>
        /// <returns>Lenght of the Vector</returns>
        public double Lenght()
        {
            Point end = new Point(EndPoint());
            return this.start_point.Distance(end);
        }

        /// <summary>
        /// Setting the vector lenght by moving the point near the arrow
        /// </summary>
        /// <param name="newlenght">New lenght of the Vector</param>
        public void SetLength(double newlenght)
        {
            this.a = angle.Cos() * newlenght;
            this.b = angle.Sin() * newlenght;
        }

        /// <summary>
        /// Gets the Ending Point of the vector
        /// </summary>
        /// <returns>Ending Point</returns>
        public Point EndPoint()
        {
            return new Point(start_point.x + a, start_point.y + b);
        }

        /// <summary>
        /// Lower Angle between 2 vectors
        /// </summary>
        public Angle AngleBetween(Vector v)
        {
            Angle ret = v.angle - angle;
            if (ret > Math.PI) return Math.PI - ret;
            else return ret;
        }

        public void Rotate(Angle rotation)
        {
            angle = angle + rotation;
            CalculAB(angle);
        }

        public void ChangeDirection()
        {
            Rotate(new Angle(Math.PI * 2));
        }
        
        /// <summary>
        /// Check if when we put vector V and calee vector in the same point,
        /// the v vector is on the left of the calee vactor
        /// </summary>
        public bool OnLeft(Vector v)
        {
            Angle check = v.angle - angle;
            if (check.val<=Math.PI)
            {
                return true;
            }
            return false;
        }

        /// <summary>
        /// Cross product on 2 vector calee X v 
        /// </summary>
        public double CrossProduct(Vector v)
        {
            return this.a * v.b - this.b * v.a;
        }

        /// <summary>
        /// Calculate Vector angle using the X and Y coordinates
        /// </summary>
        private void CalculAngle()
        {
            double tan = b / a;
            angle.val = Math.Atan(tan);
            if (b >= 0 && a >= 0)
            {
                angle.val = Math.Atan(tan);
            }
            if (b < 0 && a >= 0)
            {
                angle.val = Math.PI * 2 + angle.val;
            }
            if (b < 0 && a < 0)
            {
                angle.val = Math.PI + angle.val;
            }
            if (b >= 0 && a < 0)
            {
                angle.val = Math.PI + angle.val;
            }
        }

        private void CalculAB(Angle an)
        {
            if (an.Quarter() == 1)
            {
                a = 1;
                double tan = an.Tan();
                b = tan * a;
                angle = new Angle(an);
            }

            if (angle.Quarter() == 2)
            {
                a = -1;
                double tan = an.Tan();
                b = tan * a;
                angle = new Angle(an);
            }

            if (an.Quarter() == 3)
            {
                a = -1;
                double tan = an.Tan();
                b = tan * a;
                angle = new Angle(an);
            }

            if (an.Quarter() == 4)
            {
                a = 1;
                double tan = an.Tan();
                b = tan * a;
                angle = new Angle(an);
            }
        }
    }
}
